package cn.mysdp.utils;

import cn.mysdp.biz.domain.SdpWorkspaceWithBLOBs;
import cn.mysdp.biz.dto.response.SdpWorkspaceQueryResponse;
import cn.mysdp.biz.facade.ProcessSQLFacadeImpl;
import com.alibaba.fastjson.JSON;
import lombok.Getter;
import lombok.Setter;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.beans.BeanUtils;
import org.springframework.util.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.lang.reflect.Field;
import java.security.Key;
import java.sql.Connection;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName:
 * @Description:
 * @Author: SDP
 * @Date: 2020-10-30
 * Table:
 * Comment:
 */
@Getter
@Setter
public class ConnectUtil {
    public static final String DB_PASSWORD_SEED = "567382";

    public static String getDatabaseName(SdpWorkspaceQueryResponse workspace, Connection connection) throws Exception {
        if (StringUtils.hasText(workspace.getDbDatabase())) {
            return workspace.getDbDatabase();
        }
        if ("org.h2.Driver".equals(workspace.getDbClassname())) {
            return "public";
        }

        String jdbcurl = getUrl(workspace).toLowerCase();
        if (jdbcurl.startsWith("jdbc:mysql://")) {
            jdbcurl = jdbcurl.substring("jdbc:mysql://".length()).split("\\?")[0];
            if (jdbcurl.split("/").length == 2) {
                return jdbcurl.split("/")[1];
            }
        }
        throw new Exception("cannot get database");
    }

    public static String getDatabaseHost(SdpWorkspaceQueryResponse workspace, Connection connection) throws Exception {
        if (StringUtils.hasText(workspace.getDbHost())) {
            return workspace.getDbHost();
        }

        String jdbcurl = getUrl(workspace).toLowerCase();
        if (jdbcurl.startsWith("jdbc:mysql://")) {
            jdbcurl = jdbcurl.substring("jdbc:mysql://".length()).split("/")[0];
            if (jdbcurl.split(":").length == 2) {
                return jdbcurl.split(":")[0];
            }
        }
        throw new Exception("cannot get database");
    }

    public static String getDatabasePort(SdpWorkspaceQueryResponse workspace, Connection connection) throws Exception {
        if (workspace.getDbPort() != null) {
            return workspace.getDbPort()+"";
        }

        String jdbcurl = getUrl(workspace).toLowerCase();
        if (jdbcurl.startsWith("jdbc:mysql://")) {
            jdbcurl = jdbcurl.substring("jdbc:mysql://".length()).split("/")[0];
            if (jdbcurl.split(":").length == 2) {
                return jdbcurl.split(":")[1];
            }
        }
        throw new Exception("cannot get database");
    }

    public static String decryptDbPassword(SdpWorkspaceWithBLOBs record) throws Exception {
        SdpWorkspaceQueryResponse newRequest = new SdpWorkspaceQueryResponse();
        BeanUtils.copyProperties(record, newRequest);
        return decryptDbPassword(newRequest);
    }

    public static String decryptDbPassword(SdpWorkspaceQueryResponse record) throws Exception {
        String dbHost = record.getDbHost();
        String dbUsername = record.getDbUsername();
        String dbPassword = record.getDbPassword();
        if (StringUtils.isEmpty(dbPassword)) {
            return dbPassword;
        }

        String data = dbPassword;

        //config
        boolean useCrypto = true;

        Cipher cipher = null;
        if (useCrypto) {
            DESKeySpec dks = new DESKeySpec((DB_PASSWORD_SEED+dbUsername).getBytes("UTF-8"));
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            Key secretKey = keyFactory.generateSecret(dks);

            cipher = Cipher.getInstance("DES/ECB/NoPadding");
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
        }
        byte[] src = Base64.decodeBase64(data);

        byte[] bytes = cipher.doFinal(src);

        String dest = new String(bytes, "UTF-8");
        return dest.trim();
    }

    public static String encryptDBPassword(String dbUsername, String dbPassword) throws Exception {
        if ("******".equals(dbPassword)) {
            return dbPassword;
        }
        if ("********".equals(dbPassword)) {
            return dbPassword;
        }
        String data = dbPassword;

        //config
        boolean useCrypto = true;

        Cipher cipher = null;
        if (useCrypto) {
            DESKeySpec dks = new DESKeySpec((DB_PASSWORD_SEED+dbUsername).getBytes("UTF-8"));
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            Key secretKey = keyFactory.generateSecret(dks);

            cipher = Cipher.getInstance("DES/ECB/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        }
        byte[] src = data.getBytes("UTF-8");

        int len = src.length;
        int diff = len % 8;
        byte[] bytes;
        byte[]newSrc = new byte[len + 32+(8 - diff)];
        for(int i = 0; i < 8-diff; i++) {
            newSrc[len + 32+i] = ' ';
        }
        for(int i = 0; i < 32; i++) {
            newSrc[i] = ' ';
        }
        System.arraycopy(src, 0, newSrc, 32, len);

        bytes = cipher.doFinal(newSrc);

        return Base64.encodeBase64String(bytes);

    }

    public static Object[] getMetaFields(ResultSetMetaData resultSetMetaData) throws Exception {
        Object[] jdbcFields = new Object[0];
        try {
            Field reflectField = resultSetMetaData.getClass().getDeclaredField("fields");
            reflectField.setAccessible(true);
            jdbcFields = (Object[]) reflectField.get(resultSetMetaData);
            return jdbcFields;

        }catch(Exception ex) {

        }

        int fieldCount = 0;
        if (resultSetMetaData != null) {
            fieldCount = resultSetMetaData.getColumnCount();
            List<ProcessSQLFacadeImpl.H2MetaField> fields = new ArrayList<>();
            for(int i = 0; i < fieldCount; i++) {
                ProcessSQLFacadeImpl.H2MetaField field = new ProcessSQLFacadeImpl.H2MetaField();
                field.setName(resultSetMetaData.getColumnName(i+1));
                field.setTableName(resultSetMetaData.getTableName(i+1));
                field.setOriginalTableName(resultSetMetaData.getTableName(i+1));
                field.setMysqlType(resultSetMetaData.getColumnType(i+1));
                fields.add(field);
            }
            jdbcFields = fields.toArray();
        }
        return jdbcFields;
    }

    public static String getUrl(SdpWorkspaceWithBLOBs request) throws Exception {
        SdpWorkspaceQueryResponse workspace = new SdpWorkspaceQueryResponse();
        BeanUtils.copyProperties(request, workspace);
        return getUrl(workspace);
    }

    public static String getUrl(SdpWorkspaceQueryResponse workspace) throws Exception {
        if (StringUtils.hasText(workspace.getDbJdbcurl())) {
            return workspace.getDbJdbcurl();
        }
        String type = workspace.getDbClassname();
        String host = workspace.getDbHost();
        Integer port = workspace.getDbPort();
        String database = workspace.getDbDatabase();
        String url = "";
        if ("com.mysql.jdbc.Driver".equals(type) || "com.mysql.cj.jdbc.Driver".equals(type)) {
            url = "jdbc:mysql://"+host+":"+port+"/"+database+"?useUnicode=true&characterEncoding=UTF8&serverTimezone=Asia/Shanghai&tcpKeepAlive=true&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true&tinyInt1isBit=false";
        } else if ("org.h2.Driver".equals(type)) {
            url = "jdbc:h2:"+database+";AUTO_SERVER=TRUE;DB_CLOSE_DELAY=-1";
        } else {
            throw new Exception("不支持的数据库驱动类："+type);
        }
        return url;
    }

}
